// es6 --  layer
// 简化uniapp 弹框 api

const comUtils = require("@/utils/common");
const layerConfig = require("./config");

/* 
    $log(opts:String[,ass:Number|Object|Function]);
    轻提示 基于 wx.showToast  支持promise
    时间参数 为 毫秒  默认消失时间为 2000ms
    使用方法
    推荐第一种 promise调用
    //"第一种"
    $log("你好").then(()=>{
        console.log("我很好啊");
    }) 
    //"第二种"
    $log("你好",()=>{
        console.log("我很好啊");
    }); 
    //"第三种" , 3000ms关闭
    /* $log("你好",3000).then(()=>{
        console.log("我很好啊");
    }); 
    //"第四种"   拼接额额外参数
    $log("你好",{
        icon:"yes"
    }).then(()=>{
        console.log("我很好啊");
    }); 
*/
function $log(opts, ass) {
  return new Promise((resolve, reject) => {
    if (opts) {
      // 默认关闭时间
      let defaultOpts = {
        // 除去 图标
        icon: "none",
        // 显示遮罩层
        mask: false,
        // 默认调用成功后  关闭时间
        duration: 2000,
      };
      // 对第一个参数进行合并
      let optsType = comUtils.toClass(opts);
      // 如果是字符串 最常用  合并到 title参数
      if (optsType == "String") {
        defaultOpts.title = opts;
      }
      // 暂时取消这个判断
      //如果是对象  直接进行合并
      else if (optsType == "Object") {
        Object.assign(defaultOpts, opts);
      } else {
        throw new TypeError("the opts must be String ");
      }
      // endFun 只有第二个参数为function类型会在promise之前 提示消失之后执行
      let endFun;
      if (ass) {
        // 对第二个参数进行合并
        let assType = comUtils.toClass(ass);
        switch (assType) {
          // 如果是数字  合并到 duration参数
          case "Number":
            defaultOpts.duration = ass;
            break;
          // 如果是函数  在提示消失后执行
          case "Function":
            endFun = ass;
            break;
          // 如果是对象   直接合并
          case "Object":
            Object.assign(defaultOpts, ass);
            break;
          default:
            throw new TypeError("the opts must be Number Object or Function");
        }
      }
      let { title, duration } = defaultOpts;
      if (title) {
        // 返回一个promise对象
        uni.showToast(
          Object.assign(defaultOpts, {
            success() {
              setTimeout(() => {
                // 如果回调函数存在 在 promise then 之前执行
                endFun && endFun();
                resolve();
              }, duration);
            },
            fail() {
              reject();
            },
          })
        );
      } else {
        throw new ReferenceError("the options title is must be required");
      }
    } else {
      throw new ReferenceError("the opts must be required");
    }
  });
}

/* 
    $showModal(opts:String:Object[,ass:Object]);
    // 对话框 基于 wx.showModal  支持promise
    // 时间参数 为 毫秒
    // 对话框原型
    // yes 与 no  在promise之前调用 

*/
function $showModal(opts, ass) {
  return new Promise((resolve, reject) => {
    if (opts) {
      let defaultOpts = {
        // 对话标题
        // title,
        // 对话内容
        // content,
        cancelColor: layerConfig.cancelColor,
        confirmColor: layerConfig.confirmColor,
      };
      // 对第一个参数进行合并
      let optsType = comUtils.toClass(opts);
      // 如果是字符串 最常用  合并到 title参数
      if (optsType == "String") {
        defaultOpts.content = opts;
        // 如果是对象  直接进行合并
      } else if (optsType == "Object") {
        Object.assign(defaultOpts, opts);
      } else {
        throw new TypeError("the opts must be String or Object");
      }
      // 如果第二个参数存在且为对象则合并  否 忽略
      if (ass) {
        if (comUtils.toClass(ass) == "Object") {
          Object.assign(defaultOpts, ass);
        } else {
          console.warn("the ass is not an object , ignored");
        }
      }
      let { content, showCancel } = defaultOpts;
      if (content) {
        uni.showModal(
          Object.assign(defaultOpts, {
            success(res) {
              let { yes, no } = defaultOpts;
              if (res.confirm) {
                yes && yes();
                resolve();
              } else if (showCancel != false && res.cancel) {
                no && no();
                reject();
              }
            },
            fail() {
              reject("interface call failed");
            },
          })
        );
      } else {
        throw new ReferenceError("the options content is must be required");
      }
    } else {
      throw new ReferenceError("the opts must be required");
    }
  });
}

/* 
    _assFunc(opts:Function);
    // 给showmodal添加静态方法 返回一个正确函数 

*/
function _assFunc(opts) {
  if (opts && typeof opts == "function") {
    return opts;
  }
}

/* 
    $alert(opts:String:Object[,yes:Function]);
    alert 与 confirm 基于 $showModal 
    alert 与 confirm 都支持 promise对象
    alert,confrim 确定事件在 then
    额外添加 yes 与 no 回调函数 简单添加一个回调
    使用方法
    推荐第一种 promise调用
    //"第一种"
    $alert("你好").then(()=>{
        console.log("我很好啊");
    }) 
    //"第二种"
    $alert("你好",()=>{
        console.log("我很好啊");
    }); 
    //"第三种" , "复杂模式改变第一个参数为对象模式"
    $alert({
        title:"提示",
        content:"hellow"
    },()=>{
        console.log("我很好啊");
    }); 
 */
function $alert(opts, yes) {
  return $showModal(opts, {
    // 隐藏取消按钮
    showCancel: false,
    // 确定回调函数
    yes: _assFunc(yes),
  });
}
/* 
    $confirm(opts:String|Object[,yes:Function,no:Function]);
    // 推荐第一种 promise调用
    // confrim 取消事件在 catch
    //"第一种"
    $confirm("你好").then(()=>{
        console.log("我很好啊");
    }).catch(()=>{
        console.log("不好了");
    })
    // //"第二种"
    $confirm("你好",()=>{
        console.log("我很好啊");
    },()=>{
        console.log("不好了");
    });
    //"第三种" , "复杂模式改变第一个参数为对象模式"
    $confirm({
        title:"提示",
        content:"hellow"
    },()=>{
        console.log("我很好啊");
    },()=>{
        console.log("不好了");
    })); 

*/

function $confirm(opts, yes, no) {
  // 直接传递参数
  return $showModal(opts, {
    // 确定回调函数
    yes: _assFunc(yes),
    // 取消回调函数
    no: _assFunc(no),
  });
}

// 失败提示
/* 
	$fail(err:String|Error|Object)
*/
function $fail(err = "请求失败") {
  const errType = comUtils.toClass(err);
  if (errType === "Error" || errType === "Object") {
    let errNotic = err.message || err.errMsg || "未知错误";
    $log(errNotic);
    throw err;
  } else if (errType === "String") {
    $log(err);
    throw Error(err);
  } else {
    throw TypeError(
      `the Error params type is must be String or Error , the params type is ${errType}`
    );
  }
}
module.exports = {
  $log,
  $alert,
  $confirm,
  $fail,
};
